// FillStrokeTool.h: interface for the CFillStrokeTool class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_FILLSTROKETOOL_H__184E23E9_823F_42F9_87ED_1914DB787660__INCLUDED_)
#define AFX_FILLSTROKETOOL_H__184E23E9_823F_42F9_87ED_1914DB787660__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "Point.h"
#include "AutoFiller.h"

/// for line segment
struct SLineInfo
{
public:
	/// start point
	SPoint	m_ptGuide1;
	/// end point
	SPoint	m_ptGuide2;
	/// actual start point
	SPoint	m_pt0;
	/// actual end point
	SPoint	m_ptEnd;

public:
	int	dx, dy;
	int	m_nWeight;
//	float	m_fMax;

//public:
//	BOOL isInRect(int x, int y);
//	static BOOL CALLBACK CheckInRange(void *lpContext, int x, int y);
};

/// to check whether a point is in the direction or not
struct SCheckInfo
{
public:
	/// x of base point
	int		x0;
	/// y of base point
	int		y0;
	/// cosine for x
	float	m_fCosine;
	/// sine for y
	float	m_fSine;

public:
	BOOL isInDirection(int x, int y) const;
	static BOOL CALLBACK CheckInRange(void *lpContext, int x, int y);
};

/// to check whether a point is in the direction or not, with corner consideration
struct SCheckEndInfo
{
public:
	/// x of end point
	int		x0;
	/// y of end point
	int		y0;
	/// width of this line
	int		w0;
	/// cosine of this line
	float	m_fCosine;
	/// sine of this line
	float	m_fSine;
	/// cosine of next line
	float	m_next_dx;
	/// sine of next line
	float	m_next_dy;

public:
	/// inner usage: 0, default; 1, (-sin, cos) is the direction of next line; -1, (sin, -cos) is.
	int		m_nInitData;

public:
	BOOL isInCorner(int x, int y);
	static BOOL CALLBACK CheckInRange(void *lpContext, int x, int y);
};

//#define CIRCLE_FILLER
#ifdef CIRCLE_FILLER
typedef BOOL (CALLBACK *LPEnumPoint)(void *lpContext, int x, int y);
struct SEnumFlag
{
public:
	SEnumFlag();
	~SEnumFlag();

public:
	int destruct();
	BOOL createCircle(int nRadius);
	BOOL enumPoint(LPEnumPoint lpfnEnum, void *lpContext, BOOL fAll) const;
	BOOL checkFlag(int x, int y) const;

protected:
	BYTE	*m_pbFlag;
	int		m_nMaxX;
	int		m_nMaxY;

protected:
	SEnumFlag(const SEnumFlag&);
	SEnumFlag& operator=(const SEnumFlag&);
};

class CCircleFiller : public CAutoFiller
{
public:
	CCircleFiller(CCheckInContour *pCheck);
	~CCircleFiller();

public:
	BOOL resetGetPoint(int x, int y, int nRadius);

protected:
	CCheckInContour	*m_pCheck;
	SPoint		m_curPoint;
	int		m_nRowBytes;

protected:
	BOOL onEnumPoint(int x, int y);
	static BOOL CALLBACK enumCirclePoint(void *lpContext, int x, int y);

protected:
	CCircleFiller(const CCircleFiller&);
	CCircleFiller& operator=(const CCircleFiller&);
};
#endif	// CIRCLE_FILLER

/// to create filling point list
class CFillStrokeTool
{
public:
	CFillStrokeTool(CCheckInContour *pCheck);
	~CFillStrokeTool();

public:
	/// to set guide points(a replace of middle lines)
	int setGuides(const SPoint *lpPoint, int nPoint);
    /// to set start point for no-guide case
    int setStartXY(short x, short y);
	/// to query filling point in order
	int getPoints(SPoint **ppPoint);
	/// to query count by 0-based group index
	int getGroupCount(int nGroupIdx) const;
	/// to free memory
	int destruct(void);

protected:
	/// the simplest filler
	CAutoFiller		m_autoFiller;
	/// line point in middle line
	SPoint	*m_pGuide;
	/// count of m_pGuide
	int		m_nGuide;
    /// start point for the simplest filler
    SPoint  mStartPt;

protected:
	/// candidate point list in filling order
	CShortPoint	m_ptList;
	/// filling flag for best filling method
	BYTE	*m_pbAllFlag;
	/// count of m_pbAllFlag
	int		m_nAllFlag;
	/// flags in stroke group
	BYTE	*m_pbGroup;
	/// maximum column count
	int		m_nMaxX;
	/// maximum row count
	int		m_nMaxY;

protected:
	BOOL createPointInList(void);
//	BOOL updateLineEnd(SLineInfo *pLine, const SLineInfo *pNext);
	/// nStrokeIndex is 0-based index of stroke parts
	BOOL appendPointListFromLineInfo(const SLineInfo& info, const SLineInfo *pNext, const SLineInfo *pSec, int nPartIndex);
	BOOL clearFlagForLaterLines(BYTE *pbFlag, const SLineInfo& info, const SLineInfo *pNext, const SLineInfo *pSec);
	void enableStartFilling(BYTE *pbFlag, const SPoint& pt0, float dx, float dy);
	void touchPoint(BYTE *pbFlag, float xFrom, float yFrom, float dx2, float dy2, float f0[][2]);
	static int selectConcavePoint(const SPoint& pt, const SPoint *pPoint, int nPoint, const float fDir1[], const float fDir2[]);
	BOOL checkConcavePoint1(BYTE *pbFlag, const SPoint& pt1, float dx, float dy, float dx2, float dy2);
	BOOL checkConcavePoint2(BYTE *pbFlag, const SLineInfo& info, float dx, float dy, float dx2, float dy2);
	BOOL checkConcavePoint3(BYTE *pbFlag, const SLineInfo& info, float dx, float dy, float dx2, float dy2);
	BOOL savePartPoint(const SLineInfo& info, int nPartIndex);

protected:
	BOOL savePoint(int x, int y, int nPartIndex);
	int createLineInfo(SLineInfo **ppLine);
	int createWeightList(short **ppnWeight, const SLineInfo *pLine);
	int getPointWeight(int x, int y, float fdx, float fdy);
	int getPointAngleWeight(int x, int y, int dx, int dy, int nMaxValue);
	int getPointDirectionWeight(int x, int y, float dx, float dy, int nMaxValue);
	BOOL getLineWeight(SLineInfo *pLine, BOOL fFirst, BOOL fTail);
	BOOL getLineBeginPoint(SLineInfo *pLine);
	BOOL getLineEndPoint(SLineInfo *pLine);

protected:
	BOOL getAllFlag(int x, int y) const;
	BOOL setAllFlag(int x, int y);

protected:
	CFillStrokeTool(const CFillStrokeTool&);
	CFillStrokeTool& operator=(const CFillStrokeTool&);
};

#endif // !defined(AFX_FILLSTROKETOOL_H__184E23E9_823F_42F9_87ED_1914DB787660__INCLUDED_)
